package com.coocare.licence.config.exception;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.coocare.licence.config.domain.AjaxResult;
import com.coocare.licence.config.i18n.I18nMessage;
import com.coocare.licence.config.plugins.idempotent.exception.IdempotentException;
import com.mysql.cj.jdbc.exceptions.MysqlDataTruncation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLSyntaxErrorException;
import java.util.List;


/**
 * @author adamdiu
 */
@RestControllerAdvice
@Slf4j
@Order(999999)
public class RRExceptionHandler {

    /**
     * 处理校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public AjaxResult<Object> handleConstraintViolationException(ConstraintViolationException e) {
        return AjaxResult.failed(e.getMessage());
    }

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(RRException.class)
    public AjaxResult<Object> handleRRException(RRException e) {
        return AjaxResult.failed(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public AjaxResult<Object> handleDuplicateKeyException(DuplicateKeyException e) {
        log.error(e.getMessage(), e);
        return AjaxResult.failed(I18nMessage.getMessage("system.data.exist"));
    }

    @ExceptionHandler(BindException.class)
    public AjaxResult<Object> bindExceptionHandler(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String messages = StringUtils.join(fieldErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).toArray(), ";");
        return AjaxResult.failed(messages);
    }

    @ExceptionHandler(Exception.class)
    public AjaxResult<Object> handleException(Exception e) {
        log.error(e.getMessage(), e);
        String message = e.getMessage();
        if (e.getCause() != null && e.getCause() instanceof MysqlDataTruncation) {
            // 捕获"Data too long"异常并抛出自定义异常
            message = I18nMessage.getMessage("system.data.too.long");
        }
        return AjaxResult.failed(message);
    }

    @ExceptionHandler(NotLoginException.class)
    public AjaxResult handlerNotLoginException(NotLoginException nle) {
        // 判断场景值，定制化异常信息
        String message = "";
        if (nle.getType().equals(NotLoginException.NOT_TOKEN)) {
            message = "auth.check";
        } else if (nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
            message = "auth.illegal";
        } else if (nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
            message = "auth.expired";
        } else if (nle.getType().equals(NotLoginException.BE_REPLACED)) {
            message = "auth.expired";
        } else if (nle.getType().equals(NotLoginException.KICK_OUT)) {
            message = "token已被踢下线";
        } else {
            message = "auth.not.exist";
        }

        // 返回给前端
        return AjaxResult.failed(401, message);
    }

    @ExceptionHandler({NotRoleException.class, NotPermissionException.class})
    public AjaxResult handlerNotRoleException(Exception nle) {
        // 打印堆栈，以供调试
        nle.printStackTrace();
        // 返回给前端
        return AjaxResult.failed(9401, "system.no.permission");
    }

    @ExceptionHandler(SQLSyntaxErrorException.class)
    public AjaxResult<Object> handleSQLSyntaxErrorException(SQLSyntaxErrorException e) {
        log.error(e.getMessage(), e);
        return AjaxResult.failed();
    }

    @ExceptionHandler(IdempotentException.class)
    public AjaxResult<Object> handleIdempotentException(IdempotentException e) {
        log.error(e.getMessage(), e);
        return AjaxResult.failed(e.getMessage());
    }
}
